//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include "MTAG_Outils.h"  //Pour MTAG_UQUICKP
#include "uQuickP.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
#define MODULE_TAG MTAG_UQUICKP
//---------------------------------------------------------------------------
#define PATH_IMP_RAPIDE   "Software\\EIC\\Imprimante rapide"
#define IMPR_CONSTRUCTEUR "Constructeur"
#define IMPR_IMPRIMANTE   "Imprimante"
#define IMPR_PORT         "Port"
#define IMPR_PAPER_HEIGHT "HauteurPapier" // 0 : 10 pouces, 1 : 12 pouces
#define IMPR_PAPER_STYLE  "StylePapier"   // 0 : française, 1 : italienne
#define IMPR_OPENPRN_BIN  "BinaryOpen"
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour être sûr que les composants créés ne
// contiennent aucune fonction virtuelle pure.
//

static inline void ValidCtrCheck(CQuickPrinter *)
{
    new CQuickPrinter(NULL);
}
//---------------------------------------------------------------------------
__fastcall CQuickPrinter::CQuickPrinter(TComponent* Owner)
    : TComponent(Owner)
{
  m_pRegistry = new TRegistry;
  // Lecture des paramètres de l'imprimante rapide
  m_pRegistry->RootKey = HKEY_LOCAL_MACHINE;
//  m_pRegistry->Access = KEY_READ;
  if ( m_pRegistry->OpenKey( PATH_IMP_RAPIDE, false)) {
    m_strConstructeur  = m_pRegistry->ReadString( IMPR_CONSTRUCTEUR);
    m_strImprimante    = m_pRegistry->ReadString( IMPR_IMPRIMANTE  );
    m_strPort          = m_pRegistry->ReadString( IMPR_PORT        );
    try          { m_ePaperHeight = static_cast<PAPER_HEIGHT>( m_pRegistry->ReadInteger( IMPR_PAPER_HEIGHT)); }
    catch ( ...) { m_ePaperHeight = PH_10INCH; }
    try          { m_ePaperStyle  = static_cast<PAPER_STYLE >( m_pRegistry->ReadInteger( IMPR_PAPER_STYLE )); }
    catch ( ...) { m_ePaperStyle  = PS_FRENCH; }
    try          { m_bBinaryOpen  = m_pRegistry->ReadInteger( IMPR_OPENPRN_BIN); }
    catch ( ...) { m_bBinaryOpen  = false; }
    m_pRegistry->CloseKey();
  }
  // Initialisation des variables de la classe
  m_pStream          = NULL;
  m_pfncOnPageHeader = NULL;
  m_pfncOnPageFooter = NULL;
  m_bBold            = false;
  m_bItalic          = false;
  m_bUnderline       = false;
  m_bInitDoc         = false;
  m_nPageFLines      = 0;
  m_eOrientation     = poPortrait;
  m_nReprisePage     = 1;
}
//---------------------------------------------------------------------------
__fastcall CQuickPrinter::~CQuickPrinter()
{
  //SaveParamsPrinter();
  delete m_pRegistry;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::SaveParamsPrinter()
{
  // Sauvegarde des paramètres de l'imprimante rapide
  m_pRegistry->RootKey = HKEY_LOCAL_MACHINE;
  m_pRegistry->OpenKey( PATH_IMP_RAPIDE, true);
  m_pRegistry->WriteString ( IMPR_CONSTRUCTEUR, m_strConstructeur  );
  m_pRegistry->WriteString ( IMPR_IMPRIMANTE  , m_strImprimante    );
  m_pRegistry->WriteString ( IMPR_PORT        , m_strPort          );
  m_pRegistry->WriteInteger( IMPR_PAPER_HEIGHT, (int)m_ePaperHeight);
  m_pRegistry->WriteInteger( IMPR_PAPER_STYLE , (int)m_ePaperStyle );
  m_pRegistry->CloseKey();
}
//---------------------------------------------------------------------------
bool __fastcall CQuickPrinter::SelectPrinter()
{
  ASSERT( !m_strFileName.IsEmpty());
  bool bSelect = SelectQuickPrinter( m_strFileName, m_strConstructeur, m_strImprimante, m_strPort, m_ePaperHeight, m_ePaperStyle);
  SaveParamsPrinter();
  return bSelect;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::SetPathFileN( const AnsiString &strPath)
{
  m_strPath = strPath;
  if ( !m_strPath.IsEmpty() && ( m_strPath[ m_strPath.Length()]!='\\')) m_strFileName = m_strPath + "\\impriman.dat";
                                                                   else m_strFileName = m_strPath +   "impriman.dat";
  char szBuffer[ 1024]; ASSERT( m_strFileName.Length()<1024);
  ::GetShortPathName( m_strFileName.c_str(), szBuffer, 1024);
  m_strFileName = AnsiString( szBuffer);
}
//---------------------------------------------------------------------------
bool __fastcall CQuickPrinter::GetPrinterParams()
{
  TDefPrinter key;
  CBtrvFile   btrvFile;
  AnsiString  strConstructeur, strImprimante;
  bool        bFindImp = false;

  ASSERT( !m_strFileName.IsEmpty());
  btrvFile.Open( TAG( 10), BTRV_R, sizeof( TDefPrinter), m_strFileName);
  btrvFile.GetFirst( TAG( 11), &m_DPParams, &key, 0);
  do {
    ExtractConstructeurPrinter( AnsiString( m_DPParams.szModele), strConstructeur, strImprimante);
    if (( m_strConstructeur==strConstructeur) && ( m_strImprimante==strImprimante)) { bFindImp = true; break; }
  } while( btrvFile.GetNext( TAG( 12), &m_DPParams, &key, 0));
  btrvFile.Close( TAG( 13));

  return bFindImp;
}
//---------------------------------------------------------------------------
void __cdecl CQuickPrinter::_Print( const char *pcszFormat, ...)
{
  if( m_nCurPage<m_nReprisePage) return;

  va_list lstArgs;
  va_start( lstArgs, pcszFormat);
  vfprintf( m_pStream, pcszFormat, lstArgs);
}
//---------------------------------------------------------------------------
bool __fastcall CQuickPrinter::StartDoc()
{
  AnsiString strInfoPort;
  int        nPos, nErr;

  m_pStream            = NULL;
  m_bLeaveConnection   = false;
  m_bRestoreConnection = false;
  // Récupère les informations de l'imprimante rapide
  if ( !GetPrinterParams()) return false;
  // Recherche du paramètre complet du port
  // ex: LPT:=xxxxxx
  switch ( _WINPLATFORM) {
    case VP_WINDOWS_95_98 : { // ** Version Windows 95 et Windows 98 **
                            TIniFile *pWinIni = new TIniFile( "WIN.INI");
                            strInfoPort = pWinIni->ReadString( "PORTS", m_strPort, EmptyStr);
                            delete pWinIni; }
                            break;
    case VP_WINDOWS_NT    : { // ** Version Windows NT **
                            TRegistry *pRegistry = new TRegistry();
                            pRegistry->RootKey   = HKEY_LOCAL_MACHINE;
                            if ( pRegistry->OpenKey( strWinNTKeyPorts, false)) {
                              strInfoPort = pRegistry->ReadString( m_strPort);
                              pRegistry->CloseKey();
                            }
                            delete pRegistry; }
                            break;
    default               : ASSERT( false); break;
  }
  AnsiString strTempDir;
  AnsiString strSaveCurrentDir( GetCurrentDir());

  strTempDir.SetLength( MAX_PATH);
  ::GetTempPath( MAX_PATH, strTempDir.c_str());
  SetCurrentDir( strTempDir);
  // Ouverture du port de communication
  if (( nPos=m_strPort.Pos( ":")) != 0) {
    // Le port n'est pas un fichier ou un chemin réseau
    // Le port n'a pas de paramètre, on ouvre simplement le nom du port à l'aide d'un fprintf
    // sinon on ouvre le chemin du port
    m_pStream = fopen( strInfoPort.IsEmpty() ? m_strPort.SubString( 1, nPos-1).c_str() : strInfoPort.c_str(), m_bBinaryOpen ? "wb" : "wt");
  } else {
    // Le port est un fichier ou un chemin réseau
    if ( strInfoPort.IsEmpty()) {
      // Le port n'a pas de paramètres
      m_nSizeBuffer = sizeof( m_szLPT3RemoteName);
      nErr = ::WNetGetConnection( "LPT3:", m_szLPT3RemoteName, &m_nSizeBuffer);
      switch ( nErr) {
        case WN_SUCCESS       : nErr = ::WNetCancelConnection( "LPT3:", FALSE);
                                if ( nErr!=WN_SUCCESS) return false;
                                m_bRestoreConnection = true;
                                break;
        case WN_NOT_CONNECTED : break;
        default               : return false;
      }
      if ( ::WNetAddConnection( m_strPort.c_str(), "", "LPT3:")!=WN_SUCCESS) {
        ::WNetAddConnection( m_szLPT3RemoteName, "", "LPT3:");
        return false;
      }
      m_pStream          = fopen( "LPT3", m_bBinaryOpen ? "wb" : "wt");
      m_bLeaveConnection = true;
    } else {
      // Sinon on ouvre le chemin du port
      m_pStream = fopen( strInfoPort.c_str(), m_bBinaryOpen ? "wb" : "wt");
    }
  }
  SetCurrentDir( strSaveCurrentDir);

  // Erreur d'ouverture du flux vers l'imprimante ?
  if( !m_pStream) {
    ::EICErreur( "Impossible d'ouvrir le port de l'imprimante !");
    return false;
  }

  m_bInitDoc = true;
  // Initialisation de l'imprimante
  PrintCtrlFile( m_DPParams.szStartFile      );
  PrintCtrl    ( m_DPParams.szCI[   IDX_INIT]);
  PrintCtrl    ( m_DPParams.szCI[ IDX_REINIT]);

  if ( m_eOrientation==poLandscape) PrintCtrl( m_DPParams.szCI[ IDX_PAYSAGE]);

  // Initialisation des variables
  m_nCurLigne  = 0;
  m_nCurPage   = 1;
  m_nSkipPage  = 0;

  if (( m_ePaperStyle==PS_ITALIA) || ( m_eOrientation==poLandscape)) {
    m_nHardLines = (int)((float)m_DPParams.sLignes   * 21.0 / 29.7);
    m_nHardCols  = (int)((float)m_DPParams.sColonnes * 29.7 / 21.0);
  } else {
    m_nHardLines = (int)m_DPParams.sLignes;
    m_nHardCols  = (int)m_DPParams.sColonnes;
  }

  m_nHardLines = m_nHardLines * ( m_ePaperHeight==PH_12INCH ? 12 : 10) / 10;
//  m_nHardCols  =  (int)m_DPParams.sColonnes;

  m_nMaxLines  = m_nHardLines - m_nPageFLines;
  m_nMaxCols   = m_nHardCols;
  m_bInitDoc   = false;

  return true;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::PrintCtrlFile( const char *szFile)
{
  ASSERT( m_pStream);

  FILE *pFile;
  char  cChar;
  AnsiString    strFileName( szFile);
  strFileName = strFileName.Trim();

  if( strFileName.IsEmpty()) return;

  if (( pFile = fopen( strFileName.c_str(), "rt"))==NULL) return;
  while (( cChar = (char)getc( pFile))!=EOF) putc( cChar, m_pStream);
  fclose( m_pStream);
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::PrintCtrl( const char *szCtrl)
{
  ASSERT( m_pStream);
  // Supprime les espaces contenus dans la chaine de contrôle
  AnsiString strCtrl( szCtrl);
  strCtrl  = strCtrl.Trim();
  if ( strCtrl.IsEmpty()) return;

  int  nLength = strCtrl.Length();
  int  nPos    = 1;
  char c0, c1, c2;

  // Envoie les caractères de la chaine de contrôle en remplaçant
  // les '/e' pas des ESC et les /0F en une valeur hexa
  while ( nPos<=nLength) {
    c0 = strCtrl[ nPos];
    if ( c0!='/') { if( m_bInitDoc) fprintf( m_pStream, "%c", c0); else _Print( "%c", c0); nPos++; } // Caractère normal
    else {
      // Traitement du caractère '/'
      c1 = strCtrl[ nPos+1];
           if ( c1=='/') { if( m_bInitDoc) fprintf( m_pStream, "/"   ); else _Print( "/"   ); nPos+=2; } // Caractère '/'
      else if ( c1=='e') { if( m_bInitDoc) fprintf( m_pStream, "\x1B"); else _Print( "\x1B"); nPos+=2; } // Caractère ESC
      else if (( c1>='0') && ( c1<='9') ||
               ( c1>='A') && ( c1<='F')) {
             c2  = strCtrl[ nPos+2];
             c0  = (char)(16 * ((( c1>='0') && ( c1<='9')) ? c1-'0' : c1-'A'+10));
             c0 += (char)      ((( c2>='0') && ( c2<='9')) ? c2-'0' : c2-'A'+10);
             if( m_bInitDoc) fprintf( m_pStream, "%c", c0); else _Print( "%c", c0); nPos+=3;
           } else nPos++; // Erreur
    }
  }
}
//---------------------------------------------------------------------------
bool __fastcall CQuickPrinter::Print( const AnsiString &strText)
{
  static bool bExecute = false;
  ASSERT( m_pStream);

  // On arrive sur une nouvelle page, on exécute l'évènement OnPageHeader
  if (( m_nCurLigne==0) && m_pfncOnPageHeader && !bExecute) { bExecute = true; m_pfncOnPageHeader( this); bExecute = false; }

  try         { _Print( "%s\n", strText.c_str()); }
  catch (...) { return false; }

  m_nCurLigne++;
  if (( m_nSkipPage==0) && ( m_nCurLigne==m_nMaxLines)) SkipPage();
  return true;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::ExecOnPageFooter()
{
  m_nSkipPage++;
  // Si l'utilisateur veut dessiner sur la fin de page
  // on déplace le curseur à la fin de la page
  if ( m_nPageFLines!=0) {
    if ( m_nCurLigne<m_nMaxLines-1)
      while( m_nCurLigne<m_nMaxLines) Print( EmptyStr);
  }
  // Lance l'évènement de fin de page
  if ( m_pfncOnPageFooter) m_pfncOnPageFooter( this);
  m_nSkipPage--;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::SkipPage()
{
  m_nSkipPage++;
  ExecOnPageFooter();
  // Passe à la page suivante
  if ( m_DPParams.sSkipPage) _Print( "\x0C");
                        else while( m_nCurLigne<(m_nMaxLines+m_nPageFLines)) Print( EmptyStr);
  m_nCurLigne = 0;
  m_nCurPage++;
  m_nSkipPage--;
}
//---------------------------------------------------------------------------
bool __fastcall CQuickPrinter::EndDoc()
{
  if ( m_nCurLigne!=0) ExecOnPageFooter();
  // Fermeture de la session imprimante
  PrintCtrl    ( m_DPParams.szCI[ IDX_TERMINE]);
  PrintCtrlFile( m_DPParams.szEndFile         );
  fclose( m_pStream); m_pStream = NULL;

  // Si le port LPT3 a été detourné, il faut rétablir la connection
  if ( m_bLeaveConnection) {
    ::WNetCancelConnection( "LPT3:", FALSE);
    if ( m_bRestoreConnection) ::WNetAddConnection( m_szLPT3RemoteName, "", "LPT3:");
  }

  return true;
}
//---------------------------------------------------------------------------
int __fastcall CQuickPrinter::GetMaxCols()
{
  return m_nMaxCols;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::SetBold( bool bValue)
{
  m_bBold = bValue;
  PrintCtrl( m_DPParams.szCI[ bValue ? IDX_GRAS_DEB : IDX_GRAS_FIN]);
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::SetItalic( bool bValue)
{
  m_bItalic = bValue;
  PrintCtrl( m_DPParams.szCI[ bValue ? IDX_ITALIK_DEB : IDX_ITALIK_FIN]);
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::SetUnderline( bool bValue)
{
  m_bUnderline = bValue;
  PrintCtrl( m_DPParams.szCI[ bValue ? IDX_SOUL_DEB : IDX_SOUL_FIN]);
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::Set10CPI()
{
  m_bInitDoc = true;
  PrintCtrl( m_DPParams.szCI[ IDX_10CPI]);
  m_nMaxCols = m_nHardCols;
  m_bInitDoc = false;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::Set12CPI()
{
  m_bInitDoc = true;
  PrintCtrl( m_DPParams.szCI[ IDX_12CPI]);
  m_nMaxCols = m_nHardCols * 12 / 10;
  m_bInitDoc = false;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::Set166CPI()
{
  m_bInitDoc = true;
  PrintCtrl( m_DPParams.szCI[ IDX_166CPI]);
  m_nMaxCols = m_nHardCols * 166 / 100;
  m_bInitDoc = false;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::Set6LPI()
{
  m_bInitDoc = true;
  PrintCtrl( m_DPParams.szCI[ IDX_6LPI]);
  m_nMaxLines = m_nHardLines - m_nPageFLines;
  m_bInitDoc = false;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::Set8LPI()
{
  m_bInitDoc = true;
  PrintCtrl( m_DPParams.szCI[ IDX_8LPI]);
  m_nMaxLines = ( m_nHardLines * 8 / 6) - m_nPageFLines;
  m_bInitDoc = false;
}
//---------------------------------------------------------------------------
void __fastcall CQuickPrinter::WantLines( int nLines)
{
  if (( m_nCurLigne+nLines)>m_nMaxLines) SkipPage();
}
//---------------------------------------------------------------------------
bool __fastcall CQuickPrinter::LandscapeIsAccepted()
{
  if ( !GetPrinterParams()) return false;
  return ( m_DPParams.szCI[ IDX_PAYSAGE][0]!='\0');
}
//---------------------------------------------------------------------------
namespace Uquickp
{
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(CQuickPrinter)};
        RegisterComponents("EIC Outils", classes, 0);
    }
}
//---------------------------------------------------------------------------
